#include "ce_core.h"
#include "ce_tester.h"

using namespace CETester;

static const int CE_POOL_NALLOC = 4096;

struct test_struct {
    uint64_t        i64;
    unsigned char   data[64];
};

CE_TESTCASE(Pool) {
    ce_pool_t      *pool;
    test_struct    *ts1, *ts2, *ts3;

    pool = ce_create_pool(sizeof(test_struct), 4096);

    EXPECT_NE(pool->free, NULL);
    EXPECT_EQ(pool->size, sizeof(test_struct));
    EXPECT_EQ(pool->nalloc, CE_POOL_NALLOC);
    EXPECT_EQ(pool->nfree, CE_POOL_NALLOC);

    ts1 = (test_struct*)ce_pool_get(pool);
    ts2 = (test_struct*)ce_pool_get(pool);

    EXPECT_EQ(pool->nalloc, CE_POOL_NALLOC);
    EXPECT_EQ(pool->nfree, CE_POOL_NALLOC - 2);

    ce_pool_put(pool, ts1);
    EXPECT_EQ(pool->free, (ce_pool_data_t*)ts1);
    EXPECT_EQ(pool->nalloc, CE_POOL_NALLOC);
    EXPECT_EQ(pool->nfree, CE_POOL_NALLOC - 1);

    ce_pool_put(pool, ts2);
    EXPECT_EQ(pool->free, (ce_pool_data_t*)ts2);
    EXPECT_EQ(pool->nalloc, CE_POOL_NALLOC);
    EXPECT_EQ(pool->nfree, CE_POOL_NALLOC);

    ts1 = (test_struct*)ce_pool_get(pool);
    EXPECT_EQ(pool->nalloc, CE_POOL_NALLOC);
    EXPECT_EQ(pool->nfree, CE_POOL_NALLOC - 1);

    ts2 = (test_struct*)ce_pool_get(pool);
    ts3 = (test_struct*)ce_pool_get(pool);
    EXPECT_EQ(pool->nalloc, CE_POOL_NALLOC);
    EXPECT_EQ(pool->nfree, CE_POOL_NALLOC - 3);

    ce_pool_put(pool, ts1);
    ce_pool_put(pool, ts2);
    ce_pool_put(pool, ts3);
    EXPECT_EQ(pool->nalloc, CE_POOL_NALLOC);
    EXPECT_EQ(pool->nfree, CE_POOL_NALLOC);

    ce_destroy_pool(pool);
}

CE_TESTCASE(PoolPerf1) {
    ce_pool_t      *pool;
    void           *data;
    uint32_t        count = 10000000;

    pool = ce_create_pool(100, 4096);

    timeval         start, end;
    uint32_t        timecost;
    gettimeofday(&start, NULL);

    for (int i = 0; i < count; ++i) {
        data = ce_pool_get(pool);
    }

    gettimeofday(&end, NULL);
    timecost = (end.tv_sec - start.tv_sec) * 1000
             + (end.tv_usec - start.tv_usec) / 1000;

    EXPECT_EQ(pool->nalloc - pool->nfree, count);
    TestPrint("free: %d, alloc: %d, timecost: %d", pool->nfree, pool->nalloc, timecost);

    ce_destroy_pool(pool);
}

CE_TESTCASE(PoolPerf2) {
    ce_pool_t      *pool;
    void           *data;
    uint32_t        count = 10000000;

    pool = ce_create_pool(100, 4096);

    timeval         start, end;
    uint32_t        timecost;
    gettimeofday(&start, NULL);

    for (int i = 0; i < count; ++i) {
        data = ce_pool_get(pool);

        ce_pool_put(pool, data);
    }

    gettimeofday(&end, NULL);
    timecost = (end.tv_sec - start.tv_sec) * 1000
             + (end.tv_usec - start.tv_usec) / 1000;

    EXPECT_EQ(pool->nalloc, CE_POOL_NALLOC);
    EXPECT_EQ(pool->nfree, CE_POOL_NALLOC);
    TestPrint("free: %d, alloc: %d, timecost: %d", pool->nfree, pool->nalloc, timecost);

    ce_destroy_pool(pool);
}

CE_TESTCASE(PoolPerf3) {
    uint32_t        count = 100000;
    timeval         start, end;
    uint32_t        timecost;
    size_t          size;

    gettimeofday(&start, NULL);
    size = 40 * 1024 * 1024;
    for (int i = 0; i < count; ++i) {
        (void)malloc(size);
    }
    gettimeofday(&end, NULL);
    timecost = (end.tv_sec - start.tv_sec) * 1000
             + (end.tv_usec - start.tv_usec) / 1000;
    TestPrint("timecost: %d", timecost);
}

int main() {
    RunAllTester();
}
